package com.chujian.framework.ws.support.rcv;

import com.chujian.framework.ws.WsMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.concurrent.ConcurrentHashMap;

/**
 * ws resp 数据中心
 */
@Slf4j
public class RcvMsgRespDataCenter {

    /**
     * 响应数据中心 reqId -> 响应体
     */
    private static final ConcurrentHashMap<String, WsMsg> respMap = new ConcurrentHashMap<>();

    /**
     * 响应计时
     */
    private final ConcurrentHashMap<String, Long> respTimeMap = new ConcurrentHashMap<>();

    /**
     * 响应对象监视器
     */
    private final Object RESPONSE_MONITOR = new Object();

    /**
     * 等待响应超时时间，单位毫秒
     */
    public static final Integer waitRespTimeOut = 10 * 1000;
    /**
     * 等待响应 wait 的时间,单位毫秒
     */
    public static final Integer waitResponseTime = 15;
    /**
     * 保留响应超时时间，单位毫秒。
     * 超出响应时间未被消费，则清除
     */
    public static final Integer keepRespTimeOut = 40 * 1000;

    // 获取响应
    public WsMsg takeResp(String reqId) {
        log.info("获取请求ID={} 的响应", reqId);

        WsMsg resp;
        long start = System.currentTimeMillis();

        int cnt = 0;
        while (true) {
            resp = respMap.remove(reqId);
            cnt++;

            // log.warn("获取请求:{}的响应:{}", reqId, resp);

            if (null != resp) {
                log.info("获取请求ID={} 的响应成功，尝试次数{}", reqId, cnt);
                break;
            }

            // 等待超时
            if (System.currentTimeMillis() - start > waitRespTimeOut) {
                log.warn("获取请求ID={} 的响应超时失败，尝试次数{}", reqId, cnt);
                break;
            }
            // 等待响应
            synchronized (RESPONSE_MONITOR) {
                try {
                    // log.warn("response_monitor wait...");
                    RESPONSE_MONITOR.wait(waitResponseTime);
                } catch (InterruptedException e) {
                    log.error("response_monitor wait fail", e);
                }
            }
        }
        return resp;
    }

    public void addResp(String reqId, WsMsg msg) {
        log.info("收到请求={} 的响应", reqId);

        respMap.put(reqId, msg);
        respTimeMap.put(reqId, System.currentTimeMillis());

        // log.info("addResp 获取reqId={}的响应：{}", reqId, respMap.get(reqId));

        // 唤醒所有等待获取结果的线程
        synchronized (RESPONSE_MONITOR) {
            RESPONSE_MONITOR.notifyAll();
        }
    }

    // +++++++++++++ Scheduled

    @Scheduled(fixedRate = 1000 * 60) // 一分钟
    public void scheduleRemoveTimeOutResp() {
        removeTimeOutResp();
    }

    /**
     * 删除超时未被取走的响应
     */
    public void removeTimeOutResp() {
        for (String reqId : respTimeMap.keySet()) {
            Long sTime = respTimeMap.get(reqId);
            // 超时
            if (System.currentTimeMillis() - sTime > keepRespTimeOut) {
                log.info("清除请求={} 的响应", reqId);

                respMap.remove(reqId);
                respTimeMap.remove(reqId);
            }
        }
    }


}
